﻿using Common.Builders.Interfaces;
using Common.Entities;
using Common.Exceptions;
using DataAccess.Repository.Interfaces;
using Infrastructure.Interfaces;
using Infrastructure.Logging;

namespace Infrastructure.Services
{
    public class UserAuthenticationProvider : IUserAuthenticationProvider
    {
        private readonly IUserRepository _userRepository;
        private readonly ISecurityKeyRepository _securityKeyRepository;
        private readonly ISecurityKeyGenerator _securityKeyGenerator;
        private readonly IUserBuilder _userBuilder;
        private readonly ILoggingService _loggingService;
        private readonly IUserEncryptor _userEncryptor;

        public UserAuthenticationProvider(IUserRepository userRepository, ISecurityKeyRepository securityKeyRepository,
                                          ISecurityKeyGenerator securityKeyGenerator, ILoggingService loggingService,
                                          IUserBuilder userBuilder, IUserEncryptor userEncryptor)
        {
            _userRepository = userRepository;
            _securityKeyRepository = securityKeyRepository;
            _securityKeyGenerator = securityKeyGenerator;
            _userBuilder = userBuilder;
            _loggingService = loggingService;
            _userEncryptor = userEncryptor;
        }

        public bool LogUserIn(User user)
        {
            try
            {
                var securedUser = _userEncryptor.SecureUser(user);
                return _userRepository.GetUserByUsernameAndPassword(securedUser.UserName, securedUser.Password) != null;
            }
            catch (DataAccessException exception)
            {
                _loggingService.ReportError(exception.Message, exception);
            }
            return false;
        }

        public bool LogUserOut(User user)
        {
            try
            {
                return _securityKeyRepository.RemoveSecurityKey(user);
            }
            catch (DataAccessException exception)
            {
                _loggingService.ReportError(exception.Message, exception);
            }
            return false;
        }

        public SecurityKey CreateSecurityKey(User user)
        {
            var securityKey = _securityKeyGenerator.GenerateSecurityKey();
            var secureUser = _userBuilder.FromUser(user).WithSecurityKey(securityKey).Build();
            try
            {
                _securityKeyRepository.SaveSecurityKeyForUser(secureUser);
            }
            catch (DataAccessException exception)
            {
                securityKey = null;
                _loggingService.ReportError(exception.Message, exception);
            }
            return securityKey;
        }

        public bool UserExists(string userName)
        {
            if(!string.IsNullOrEmpty(userName))
            {
                try
                {
                    return _userRepository.UserExists(userName);
                }
                catch (DataAccessException exception)
                {
                    _loggingService.ReportError(exception.Message, exception);
                }
            }
            return false;
        }
    }
}
